package com.zjw.zy.heart.configuration;

import com.zjw.zy.heart.domain.User;
import com.zjw.zy.heart.wbsocket.socket.WsMessage;
import com.zjw.zy.heart.utils.JsonUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;

import java.nio.charset.StandardCharsets;

@Configuration
@EnableCaching
public class HeartRedisConfiguration extends RedisStandaloneConfiguration {

    @Value("${spring.data.redis.host}")
    public String host;

    @Value("${spring.data.redis.port}")
    public int port;

    @Value("${spring.data.redis.password}")
    public String password;

    @Bean
    public RedisConnectionFactory redisConnectionFactory() {
        JedisConnectionFactory factory = new JedisConnectionFactory();
        factory.setPort(port);
        factory.setHostName(host);
        factory.setPassword(password);
        return factory;
    }

    @Bean("wechat-cache")
    public RedisTemplate<String, WsMessage> redisKeyValueTemplate1(RedisConnectionFactory factory) {
        RedisTemplate<String, WsMessage> redisTemplate = new RedisTemplate<>();

        redisTemplate.setConnectionFactory(factory);
        redisTemplate.setKeySerializer(RedisSerializer.string());
        redisTemplate.setHashKeySerializer(RedisSerializer.string());

        WsMessageSerializer wsMessageSerializer = new WsMessageSerializer();
        redisTemplate.setValueSerializer(wsMessageSerializer);
        redisTemplate.setHashValueSerializer(wsMessageSerializer);

        return redisTemplate;
    }

    @Bean("user-cache")
    public RedisTemplate<String, User> redisKeyValueTemplate2(RedisConnectionFactory factory) {
        RedisTemplate<String, User> redisTemplate = new RedisTemplate<>();

        redisTemplate.setConnectionFactory(factory);
        redisTemplate.setKeySerializer(RedisSerializer.string());
        redisTemplate.setHashKeySerializer(RedisSerializer.string());

        UserCacheSerializer userCacheSerializer = new UserCacheSerializer();
        redisTemplate.setValueSerializer(userCacheSerializer);
        redisTemplate.setHashValueSerializer(userCacheSerializer);

        return redisTemplate;
    }

    @Bean("c2c-cache")
    public RedisTemplate<String, WsMessage> redisKeyValueTemplate3(RedisConnectionFactory factory) {
        RedisTemplate<String, WsMessage> redisTemplate = new RedisTemplate<>();

        redisTemplate.setConnectionFactory(factory);
        redisTemplate.setKeySerializer(RedisSerializer.string());
        redisTemplate.setHashKeySerializer(RedisSerializer.string());

        WsMessageSerializer wsMessageSerializer = new WsMessageSerializer();
        redisTemplate.setValueSerializer(wsMessageSerializer);
        redisTemplate.setHashValueSerializer(wsMessageSerializer);

        return redisTemplate;
    }


    private static class WsMessageSerializer implements RedisSerializer<WsMessage> {
        @Override
        public byte[] serialize(WsMessage message) throws SerializationException {
            if (message == null) {
                return new byte[]{};
            }
            String s = message.toJson();
            return s.getBytes(StandardCharsets.UTF_8);
        }

        @Override
        public WsMessage deserialize(byte[] bytes) throws SerializationException {
            if (bytes == null) {
                return null;
            }
            String s = new String(bytes, StandardCharsets.UTF_8);
            return WsMessage.obtainFromString(s);
        }
    }

    private static class UserCacheSerializer implements RedisSerializer<User> {
        @Override
        public byte[] serialize(User user) throws SerializationException {
            return JsonUtils.toJson(user).getBytes(StandardCharsets.UTF_8);
        }

        @Override
        public User deserialize(byte[] bytes) throws SerializationException {
            if (bytes == null) {
                return null;
            }
            return JsonUtils.fromJson(new String(bytes, StandardCharsets.UTF_8), User.class);
        }
    }
}
